macro 'Display Calibration Table';
{
Stores 0-255(all possible gray values) in the User1 column
and the 256 corresponding calibrated values in the User2 column.
Max Measurements must be set to 256 or greater. Use the Export
command to export the calibration table to a text file. The two
columns will be identical if the image is not calibrated.
}
var
  i:integer;
  v:real;
begin
  RequiresVersion(1.44);
  SetCounter(256);
  SetUser1Label('value');
  SetUser2Label('cvalue');
  for i:=0 to 255 do begin
    rUser1[i+1]:=i;
    rUser2[i+1]:=cvalue(i);
  end;
  ShowResults;
end;


macro 'Measure and draw line [L]';
var
  x1,x2,y1,y2,width:integer;
begin
  GetLine(x1,y1,x2,y2,width);
  if x1<0 then begin
    PutMessage('This macro requires a straight line selection.');
    exit;
  end;
  Measure;
  Fill;
  KillRoi;
end;

macro 'Measure and Outline [M]';
begin
  Measure;
  DrawBoundary;
  DrawBoundary;
end;


macro 'Measure All';
{Measures all currently open images using the current selection. There is}
{an implied "Select All" if the active image doesn't have a selection.}
var
  i,left,top,width,height:integer;
begin
  ResetCounter;
  for i:=1 to nPics do begin
    SelectPic(i);
    RestoreROI;
    Measure;
  end;
end;


macro 'Measure All from Disk';
{
Reads from disk and measures a set of images too large to simultaneously
fit in memory. The image names names must be in the form '01', '02', etc.
Before starting, open and outline the first image('01').
}
var
  i,width,height:integer;
begin
  GetPicSize(width,height);
  if width=0 then begin
    PutMessage('Before running this macro, open and outline the first image("01") in the series.');
    exit;
  end;
  ResetCounters;
  Measure;
  close;
  for i:=2 to 1000 do begin
    open(i:2);
    RestoreROI;
    Measure;
    close;
  end;
end;


macro 'Paste Results'
{Use the Measure command, the ruler tool, or the pointing tool to}
{make up to about 10 measurements, then use this macro to paste}
{the results into the upper left corner of the window.}
begin
  SetFont('Monaco');
  SetFontSize(9);
  SetText('Plain; Align Left');
  SetOption; {Copy headings}
  CopyResults;
  MakeRoi(-10,0,250,150);
  Paste;
  KillRoi;
  ResetCounter;
end;


macro 'Measure Redirected and Label'
begin
  Redirect(true);
  Measure;
  Redirect(false);
  MarkSelection;
  RestoreRoi;
end;


macro 'Reset Measurement Options';
{Resets the Options dialog box in the Analyze menu to the default settings.}
begin
  RequiresVersion(1.44);
  SetOptions('Area; Mean');
  Redirect(false);
  LabelParticles(true);
  OutlineParticles(false);
  IgnoreParticlesTouchingEdge(false);
  IncludeInteriorHoles(false);
  WandAutoMeasure(false);
  AdjustAreas(false);
  SetParticleSize(1,999999);
  SetPrecision(2);
end;


macro 'Set Threshold';
var
  lower,upper:integer;
begin
  lower:=GetNumber('Lower:',1);
  upper:=GetNumber('Upper:',254);
  SetDensitySlice(lower,upper);
end;


macro 'Measure Accumulated Perimeter[A]';
{
Measures perimeter and computes accumulated perimeter,
storing it in the User1 column.
}
var
  i:integer;
  Total:real;
begin
  SetOptions('Area; Mean; Perimeter; User1');
  SetUser1Label('Total');
  Measure;
  Total:=0;
  for i:=1 to rCount do Total:=Total+rLength[i];
  rUser1[rCount]:=Total;
  UpdateResults;
end;


macro 'Count Black and White Pixels [B]';
{
Counts the number of black and white pixels in the current
selection and stores the counts in the User1 and User2 columns.
}
begin
  RequiresVersion(1.44);
  SetUser1Label('Black');
  SetUser2Label('White');
  Measure;
  rUser1[rCount]:=histogram[255];
  rUser2[rCount]:=histogram[0];
  UpdateResults;
end;


macro 'Compute Percent Black and White';
{
Computes the percentage of back and white pixels in the
current selection. This macro only works with binary images.
}
var
  nPixels,mean,mode,min,max:real;
begin
  RequiresVersion(1.44);
  SetUser1Label('Black');
  SetUser2Label('White');
  Measure;
  GetResults(nPixels,mean,mode,min,max);
  rUser1[rCount]:=histogram[255]/nPixels;
  rUser2[rCount]:=histogram[0]/nPixels;
  UpdateResults;
  if (histogram[0]+histogram[255])<>nPixels
    then PutMessage('This macro requires a binary image.');
end;


macro 'Compute Area Percentage [P]';
{
Computes the percentage of foreground
pixels in the current selection.
}
var
  mean,mode,min,max:real;
  i,lower,upper,fPixels,nPixels,count:integer;
begin
  RequiresVersion(1.50);
  SetUser1Label('%');
  Measure;
  GetResults(nPixels,mean,mode,min,max);
  GetThresholds(lower,upper);
  if (lower=0) and (upper=0) and 
     ((histogram[0]+histogram[255])<>nPixels)
     then begin
       PutMessage('This macro requires a binary or thresholded image.');
       exit;
     end;
  if nPixels=0 then begin
  end;
  if (lower=0) and (upper=0) then begin
    if nPixels=0
      then rUser1[rCount]:=0
      else rUser1[rCount]:=(histogram[255]/nPixels)*100;
    UpdateResults;
    exit;
  end;
  fPixels:=0;
  nPixels:=0;
  for i:=0 to 255 do begin
    count:=histogram[i];
    nPixels:=nPixels+count;
    if (i>=lower) and (i<=upper)
      then fPixels:=fPixels+count;
  end;
  rUser1[rCount]:=(fPixels/nPixels)*100;
  UpdateResults;
end;


macro 'Compute Average and Total Area [T]';
{
Computes average and accumulated area and stores 
the them in the Major and Minor Axis columns.
}
var
  i:integer;
  sum:real;
begin
  RequiresVersion(1.44);
  SetUser1Label('Avg');
  SetUser2Label('Total');
  SetOptions('Area; User1; User2');
  Measure;
  sum:=0;
  for i:=1 to rCount do sum:=sum+rArea[i];
  rUser1[rCount]:=sum/rCount;
  rUser2[rCount]:=sum;
  UpdateResults;
end;


macro 'Measure Circularity';
begin
  SetUser1Label('Shape');
  Measure;
  rUser1[rCount]:=4*3.14159265*(rArea[rCount]/sqr(rLength[rCount]));
  UpdateResults;
end;


macro 'Measure Sum of Pixel Values';
begin
  SetUser1Label('Mean*Area');
  Measure;
  rUser1[rCount]:=rMean[rCount]*rArea[rCount];
  UpdateResults;
end;

macro 'Draw XY Center';
var
  left, top, width, height, x, y: integer;
  scale: real;
  unit: string;
begin
  GetRoi(left,top,width,height);
  if width=0 then begin
    PutMessage('This macro requires a selection.');
    exit;
  end;
  SaveState;
  InvertY(false);
  SetForegroundColor(255); {black}
  SetOptions('Area; Mean; X-Y Center');
  GetScale(scale, unit);
  Measure;
  KillRoi;
  x := round(rX[rCount] * scale);
  y := round(rY[rCount] * scale);
  MoveTo(x-5, y);
  LineTo(x+5, y);
  MoveTo(x, y-5);
  LineTo(x, y+5);
  RestoreState;
end;


macro 'Compute Spatial Scale';
var
  scale:real;
begin
  MakeLineRoi(0,0,100,0);
  Measure;
  KillRoi;
  Scale:=100/rLength[rCount];
  if scale=1
    then PutMessage('Image is not spatially calibrated')
    else PutMessage('Scale=',scale:1:4,' pixels/unit');
end;


procedure StoreZeros;
begin
  Measure;
  rArea[rCount]:=0;
  rMean[rCount]:=0;
  rStdDev[rCount]:=0;
  rX[rCount]:=0;
  rY[rCount]:=0;
  rLength[rCount]:=0;
  rMajor[rCount]:=0;
  rMinor[rCount]:=0;
  rAngle[rCount]:=0;
  rUser1[rCount]:=0;
  rUser2[rCount]:=0;
  UpdateResults;
end;

macro 'Store Break in Results [S]';
{Stores a row of zeros in the results table.}
begin
  StoreZeros;
end;

macro 'Compute Means';
var
  n,i:integer;
begin
  n:=rCount;
  StoreZeros;
  StoreZeros;
  for i:=1 to n do begin
    rArea[rCount]:=rArea[rCount]+rArea[i];
    rMean[rCount]:=rMean[rCount]+rMean[i];
    rStdDev[rCount]:=rStdDev[rCount]+rStdDev[i];
    rX[rCount]:=rX[rCount]+rX[i];
    rY[rCount]:=rY[rCount]+rY[i];
    rLength[rCount]:=rLength[rCount]+rLength[i];
    rMajor[rCount]:=rMajor[rCount]+rMajor[i];
    rMinor[rCount]:=rMinor[rCount]+rMinor[i];
    rAngle[rCount]:=rAngle[rCount]+rAngle[i];
    rUser1[rCount]:=rUser1[rCount]+rUser1[i];
    rUser2[rCount]:=rUser2[rCount]+rUser2[i];
  end; 
  rArea[rCount]:=rArea[rCount]/n;
  rMean[rCount]:=rMean[rCount]/n;
  rStdDev[rCount]:=rStdDev[rCount]/n;
  rX[rCount]:=rX[rCount]/n;
  rY[rCount]:=rY[rCount]/n;
  rLength[rCount]:=rLength[rCount]/n;
  rMajor[rCount]:=rMajor[rCount]/n;
  rMinor[rCount]:=rMinor[rCount]/n;
  rAngle[rCount]:=rAngle[rCount]/n;
  rUser1[rCount]:=rUser1[rCount]/n;
  rUser2[rCount]:=rUser2[rCount]/n;
  UpdateResults;
end;

macro 'Measure both Raw and Calibrated';
{
This macro is a variation of the Measure command that displays the number
of pixels in User1 and uncalibrated (raw) mean density in User2. It takes
advantage of the fact that GetResults always returns uncalibrated values.
}
var
  nPixels,mean,mode,min,max:real;
begin
  SetUser1Label('Pixels');
  SetUser2Labe2('Raw Mean');
  Measure;
  GetResults(nPixels,mean,mode,min,max);
  rUser1[rCount]:=nPixels;
  rUser2[rCount]:=mean;
  UpdateResults;
end;


macro 'Mark Centers';
{Replaces each object in the image with a single pixel.}
var i:integer;
begin
   Duplicate('Center');
   SetScale(0,'pixels');
   AutoThreshold;
   AnalyzeParticles;
   SelectAll;
   Clear;
   For i:=1 to rCount do
      PutPixel(rX[i],rY[i],255);
end;

macro 'Density Slice [D]';
var
  t1,t2:integer;
begin
  GetThresholds(t1,t2);
  if (t1=0) and (t2=0) 
    then SetDensitySlice(255,255)
    else SetDensitySlice(0,0);
end;

macro 'Set Scale and Aspect Ratio';
{
Sets the spatial scale and aspect ratio to predefined
values contained in an image names "scale". This image
can be very small, say 20x10. The directory (folder) path
in the open statement will probably have to be changed.
}
begin
  open('hd400:image:scale');
  PropagateSpatial;
  Dispose;
end;

macro 'Write Results to Text Window';
{This is an example of how to save results in a text window.}
var
  year,month,day,hour,minute,second,dow:integer;
begin
  GetTime(year,month,day,hour,minute,second,dow);
  Measure;
  NewTextWindow('My Results');
  writeln('Date=',year-1900:1,':',month:1,':',day:1);
  writeln('Time=',hour:1,':'minute:1,':',second:1);
  writeln('Area=',rArea[rCount]:1:3);
  writeln('Mean=',rMean[rCount]:1:3);
end;


macro 'Find Radial Distances';
{Finds center to edge distances along radial lines and displays them in User1.} 
var
   RoiLeft, RoiTop, RoiWidth, RoiHeight: integer;
   x1, y1, x2, y2, count, ppv: integer;
   pi, angle, delta, min, max, scale: real;
   line, i,nLines, radius, r: integer;
   unit: string;
begin
   SaveState;
   GetRoi(RoiLeft, RoiTop, RoiWidth, RoiHeight);
   if RoiWidth=0 then begin
      PutMessage('Selection Required.');
      exit;
   end;
   GetScale(scale, unit);
   MoveRoi(-RoiLeft, -RoiTop);
   KillRoi;
   RestoreRoi;
   SetForegroundColor(255);
   SetBackgroundColor(0);
   SetNewSize(RoiWidth, RoiHeight);
   MakeNewWindow('Temp');
   RestoreRoi;
   SetOptions('X-Y Center');
   InvertY(false);
   Measure;
   DrawBoundary;
   KillRoi;
   x1:=rX[rCount] * scale;
   y1:=rY[rCount] * scale;
   radius:=sqrt(sqr(x1)+sqr(y1));
   r:=sqrt(sqr(RoiWidth-x1)+sqr(y1));
   if r > radius then radius := r;
   r := sqrt(sqr(RoiWidth-x1) + sqr(RoiHeight - y1));
   if r > radius then radius := r;
   r := sqrt(sqr(x1) + sqr(RoiHeight - y1));
   if r > radius then radius := r;
   nLines := GetNumber('Number of Radial Lines:', 36);
   pi := 3.14159;
   delta := 2.0 * pi / nLines;
   angle := 0.0;
   ResetCounter;
   SetUser1Label('Dist.');
   SetOptions('User1');
   for line := 1 TO nLines do begin
      x2 := x1 + round(radius * cos(angle));
      y2 := y1 + round(radius * sin(angle));
      MakeLineRoi(x1, y1, x2, y2);
      GetPlotData(count, ppv, min, max);
      Fill;
      i := count;
      repeat
         i := i - 1;
      until (i <= 0) or (PlotData[i] > 0);
      rUser1[line] := i;
      angle:=angle + delta;
   end;
   KillRoi;
   if scale <> 1 then
      for i := 1 to nLines do rUser1[i] := rUser1[i] / scale;
   SetCounter(nLines);
   RestoreState;
   ShowResults;
end;


Macro 'Copy Results to Clipboard with Headers';
begin
  SelectWindow('Results');
  SetOption; Copy;
end;

Macro 'Export Results with Headers';
begin
  SetExport('Measurements');
  SetOption; Export('HD80:Image:Results');
end;

macro 'Feret Dimensions [F]';
var
   xloc,yloc,width,height:integer;
begin
  SetUser1Label('X Feret');
  SetUser2Label('Y Feret');
  Measure;
  GetRoi(xloc,yloc,width,height);
  rUser1[rCount]:=width;
  rUser2[rCount]:=height;
  UpdateResults;
end;

macro 'Bounding Rectangle';
var
   xloc,yloc,width,height:integer;
begin
   GetRoi(xloc,yloc,width,height);
   ShowMessage('xmin=', xloc, '\ymin=', yloc,
       '\xmax=', xloc+width-1, '\ymax=', yloc+height-1);
 end;


macro 'Calculate Alternate Mean [C]';
{
There are two ways to calculate the mean of a density calibrated image: (1) Convert all the pixels to calibrated values, then calculate the mean; (2) Calculate the mean gray value, then convert this single value to a calibrated value. NIH Image normally uses the first method. This macro calculates the mean using the second method and displays it in the User1 column in the Results window. It also displays the percent difference between the two means in the User2 column.
}
var
   nPixels,mean,mode,min,max:real;
begin
  SetUser1Label('Mean2');
  SetUser2Labe2('%diff');
  Measure;
  GetResults(nPixels,mean,mode,min,max);
  if calibrated then
     rUser1[rCount]:=cvalue(round(mean))
  else
     rUser1[rCount] := mean;
  if rMean[rCount] <> 0 then
     rUser2[rCount] := (rUser1[rCount] - rMean[rCount]) /  rMean[rCount] * 100
  else
     rUser2[rCount] := 0;
  UpdateResults;
end;

